const fs = require('fs')
const path = require('path')

const fileUtils = require('./file')
const common = require('./common')
const error = require('./error')

// 目录结构
class Folder {
  constructor (settingFilePath, outputPath, filePath, fileHead, fileTail = 'json') {
    // 目录设置文件的路径
    this.settingFilePath = settingFilePath
    // 输出文件路径
    this.outputPath = outputPath
    // 单元文件所在路径
    this.filePath = filePath
    // 单元文件名的前缀
    this.fileHead = fileHead
    // 单元文件名的后缀名
    this.fileTail = fileTail
  }
  
  // 初始化，读文件
  async init () {
    // 获取目录结构数据
    let data = await fs.promises.readFile(this.settingFilePath)
    data = JSON.parse(data)
    this.settings = data
  }
  
  // 保存目录结构数据
  async save () {
    const buffer = JSON.stringify(this.settings)
    await fs.promises.writeFile(this.settingFilePath, buffer)
  }
  
  // 根据名字name, 创建一个新节点
  initItem (name) {
    // id为当前时间戳 + 8位随机串
    const id = new Date().getTime() + common.randomString(false, 8)
    return {
      id: id,
      name: name,
      children: []
    }
  }
  
  // 从文件中获取数据
  async getFileData (id) {
    // 如果节点下有相应的文件,一并删除
    const fileName = this.fileHead + '_' + id + '.' + this.fileTail
    const filePath = this.filePath + fileName
    let data = await fs.promises.readFile(filePath)
    data = JSON.parse(data)
    return data
  }
  
  // 添加一个新节点
  // 在id为parentId节点中插入名为name的新节点
  async addChild (parentId, name) {
    if (!this.settings) {
      return Promise.reject(error('FOLDER_UNDEFINED', '目录数据未成功初始化'))
    }
    
    // 创建新地图
    const newItem = this.initItem(name)
    if (!parentId) {
      // 未指定parentId，添加到根节点
      this.settings.push(newItem)
    }
    else {
      // 找到父节点，插入子节点
      let parentItem = this.getById(parentId)
      if (parentItem) {
        parentItem.children.push(newItem)
      }
    }
    // 因为数据发生了更改,保存
    await this.save()
  }
  
  // 重命名某一个节点
  async rename (id, name) {
    let item = this.getById(id)
    if (!item) {
      return Promise.reject(error('ITEM_NO_EXISTS', '目录中找不到相应节点', id))
    }
    
    item.name = name
    
    // 因为数据发生了更改,保存
    await this.save()
  }
  
  // 删除某一节点
  async delete (id) {
    let data = this.getParentById(id)
    if (!data) {
      return Promise.reject(error('ITEM_NO_EXISTS', '目录中找不到相应节点', id))
    }
    
    // 该数组用于检测节点是否成功删除
    let spliceArr = data.obj.splice(data.index, 1)
    
    if (spliceArr.length > 0 && spliceArr[0]) {
      // 递归删除文件
      await this.deleteFile(spliceArr[0])     
    }
    
    // 因为数据发生了更改,保存
    await this.save()
  }
  
  // 递归删除文件
  async deleteFile (obj) {
    if (obj.file) {
      const filePath = this.filePath + obj.file
      await fs.promises.unlink(filePath)      
    }
    
    // 下级的key是children
    if (obj.children) {
      const progresses = []
      const len = obj.children.length
      for (let i = 0; i < len; i++) {
        let progress = this.deleteFile(obj.children[i])
        progresses.push(progress)
      }
      await Promise.all(progresses)
    }
  }
  
  // 添加一个文件
  async addFile (id, data) {
    let item = this.getById(id)
    if (!item) {
      return Promise.reject(error('ITEM_NO_EXISTS', '目录中找不到相应节点', id))
    }
    
    // 记录文件
    const fileName = this.fileHead + '_' + id + '.' + this.fileTail
    const filePath = this.filePath + fileName
    item.file = fileName
    
    const buffer = JSON.stringify(data)
    await fs.promises.writeFile(filePath, buffer)
    
    // 因为数据发生了更改,保存
    await this.save()
  }
  
  // 输出
  async output (id, data) {
    // 检测输出目录的存在性,如果不存在,创建一个
    await fileUtils.createFolder(this.outputPath)
    
    // 拼接文件名
    const fileName = this.fileHead + '_' + id + '.' + this.fileTail
    const outputPath = this.outputPath + fileName
    const buffer = JSON.stringify(data)
    await fs.promises.writeFile(outputPath, buffer)
  }
  
  // 获取所有文件
  async getFiles () {
    let files = await fs.promises.readdir(this.filePath)
    // 剔除配置文件
    const settingName = path.basename(this.settingFilePath)
    const settingIndex = files.indexOf(settingName)
    files.splice(settingIndex, 1)
    
    return files
  }
  
  // 根据id,递归从settings数据中找到相应的对象
  getById (id) {
    if (!this.settings) {
      return null
    }
    
    const len = this.settings.length
    
    for (let i = 0; i < len; i++) {
      let result = this.findById(this.settings[i], id)
      if (result) {
        return result
      }
    }
    
    return null
  }
  
  // 深度递归
  findById (obj, id) {
    if (obj.id === id) {
      return obj
    }
    
    // 下级的key是children
    if (obj.children) {
      const len = obj.children.length
      for (let i = 0; i < len; i++) {
        let result = this.findById(obj.children[i], id)
        if (result) {
          return result
        }
      }
    }
    
    return null
  }
  
  // 递归，根据id查找目标的父节点
  getParentById (id) {
    if (!this.settings) {
      return null
    }
    
    // 根节点中寻找
    const index = this.settings.findIndex(item => item.id === id)
    if (index >= 0) {
      return {
        index: index,
        obj: this.settings
      }
    }
    
    const len = this.settings.length
    // 递归遍历子节点
    for (let i = 0; i < len; i++) {
      let result = this.findParentById(this.settings[i], id)
      if (result) {
        return result
      }
    }
    
    return null
  }
  
  findParentById (obj, id) {
    if (obj.children) {
      const index = obj.children.findIndex(item => item.id === id)
      if (index >= 0) {
        return {
          index: index,
          obj: obj.children
        }
      }
           
      const len = obj.children.length
      for (let i = 0; i < len; i++) {
        let result = this.findParentById(obj.children[i], id)
        if (result) {
          return result
        }
      }
    }
    
    return null
  }
}

module.exports = Folder